/*
 * Copyright (C) 2021 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @addtogroup power
 * @{
 *
 * @brief Provides device power management functions.
 *
 * This module is used to reboot the device and set low power consumption for the device. \n
 *
 * @since 2.2
 * @version 2.2 */
#include "iot_errno.h"
#include "lowpower.h"

#include "pm/pm.h"
#include "driver/chip/hal_prcm.h"
#include "driver/chip/hal_wakeup.h"

#define USER_SLEEP 0
#define USER_STANDBY 0
#define USER_HIBERNATION 0
#define USER_STANDBY_DTIM 0

#define WAKEUP_IO_PIN_DEF (5)
#define WAKEUP_IO_MODE_DEF (WKUPIO_WK_MODE_FALLING_EDGE)
#define WAKEUP_IO_PULL_DEF (GPIO_PULL_UP)
#define BUTTON_WAKEUP_PORT_DEF GPIO_PORT_A
#define BUTTON_WAKEUP_PIN_DEF WakeIo_To_Gpio(WAKEUP_IO_PIN_DEF)

/**
 * @brief setup wakeup source to timer which after 10 second will create irq.
 *
 * @param none
 *
 * @retval None.
 */
static void pm_wakeup_timer_init(void)
{
	/*wakeup timer 10 seconds*/
	HAL_Wakeup_SetTimer_mS(10000);
}

/**
 * @brief disable wakeup source to timer.
 *
 * @param none
 *
 * @retval None.
 */
static void pm_wakeup_timer_deinit(void)
{
	HAL_Wakeup_ClrTimer();
}

/**
 * @brief setup wakeup source to button which after 10 second will create irq.
 *
 * @param none
 *
 * @retval None.
 */
static void pm_wakeup_button_init(void)
{
	GPIO_InitParam param;
	param.driving = GPIO_DRIVING_LEVEL_1;
	param.pull = GPIO_PULL_UP;
	param.mode = GPIOx_Pn_F0_INPUT;
	HAL_GPIO_Init(BUTTON_WAKEUP_PORT_DEF, BUTTON_WAKEUP_PIN_DEF, &param);

	/*Sakeup io debounce clock source 0  freq is LFCLK 32K*/
	HAL_PRCM_SetWakeupDebClk0(0);
	/*Wakeup IO 5 debounce clock select source 0*/
	HAL_PRCM_SetWakeupIOxDebSrc(WAKEUP_IO_PIN_DEF, 0);
	/*Wakeup IO 5 input debounce clock cycles is 16+1*/
	HAL_PRCM_SetWakeupIOxDebounce(WAKEUP_IO_PIN_DEF, 1);
	/*Wakeup IO 5 enable, negative edge,  */
	HAL_Wakeup_SetIO(WAKEUP_IO_PIN_DEF, WAKEUP_IO_MODE_DEF,
			 WAKEUP_IO_PULL_DEF);
}

/**
 * @brief disable wakeup source to button.
 *
 * @param none
 *
 * @retval None.
 */
static void pm_wakeup_button_deinit(void)
{
	/*Sakeup io debounce clock source 0  freq is LFCLK 32K to default*/
	HAL_PRCM_SetWakeupDebClk0(0);
	/*Wakeup IO 5 debounce clock select source 0 to default*/
	HAL_PRCM_SetWakeupIOxDebSrc(WAKEUP_IO_PIN_DEF, 0);
	/*Wakeup IO 5 input debounce clock cycles to default*/
	HAL_PRCM_SetWakeupIOxDebounce(WAKEUP_IO_PIN_DEF, 0);

	HAL_GPIO_DisableIRQ(BUTTON_WAKEUP_PORT_DEF, BUTTON_WAKEUP_PIN_DEF);
	HAL_GPIO_DeInit(BUTTON_WAKEUP_PORT_DEF, BUTTON_WAKEUP_PIN_DEF);
}

/**
 * @brief Initializes low power consumption.
 *
 * @return Returns {@link IOT_SUCCESS} if low power consumption is initialized;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int LpcInit(void)
{
	pm_wakeup_timer_init();
	/* pm_wakeup_button_init(); */

	return IOT_SUCCESS;
}

/**
 * @brief Sets low power consumption for the device.
 *
 * @param type Indicates the low power consumption mode, as enumerated in {@link LpcType}.
 * @return Returns {@link IOT_SUCCESS} if low power consumption is set;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int LpcSetType(LpcType type)
{
	int ret;

	switch (type) {
	case LIGHT_SLEEP: {
		ret = pm_enter_mode(PM_MODE_SLEEP);
		if (!ret) {
			printf("Wakeup event:%d\n", HAL_Wakeup_GetEvent());
			pm_wakeup_timer_deinit();
			/* pm_wakeup_button_deinit(); */
		} else {
			return IOT_FAILURE;
		}
	} break;

	case DEEP_SLEEP: {
		ret = pm_enter_mode(PM_MODE_STANDBY);
		if (!ret) {
			printf("Wakeup event:%d\n", HAL_Wakeup_GetEvent());
			pm_wakeup_timer_deinit();
			/* pm_wakeup_button_deinit(); */
		} else {
			return IOT_FAILURE;
		}
	} break;

	default:
		break;
	}

	return IOT_SUCCESS;
}

/** @} */
